package com.ksana.bean.factory.xml;

import cn.hutool.core.util.XmlUtil;
import com.ksana.bean.BeanException;
import com.ksana.bean.PropertyValue;
import com.ksana.bean.factory.BeanFactory;
import com.ksana.bean.factory.config.BeanDefinition;
import com.ksana.bean.factory.config.BeanReference;
import com.ksana.bean.factory.support.AbstractBeanDefinitionReader;
import com.ksana.bean.factory.support.DefaultListableBeanFactory;
import com.ksana.core.DefaultResourceLoader;
import com.ksana.core.Resource;
import com.ksana.core.ResourceLoader;
import com.ksana.util.StringUtil;
import org.w3c.dom.*;

import java.io.IOException;

public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
    public XmlBeanDefinitionReader(DefaultListableBeanFactory registry) {
        super(registry);
    }

    @Override
    public void loadBeanDefinitions(Resource resource) {
        doLoadBeanDefinitions(resource);
    }

    @Override
    public void loadBeanDefinitions(Resource... resources) {
        for (Resource resource : resources) {
            doLoadBeanDefinitions(resource);
        }
    }

    @Override
    public void loadBeanDefinitions(String location) {
        doLoadBeanDefinitions(new DefaultResourceLoader().getResource(location));
    }

    @Override
    public void loadBeanDefinitions(String... locations) {
        for (String location : locations) {
            loadBeanDefinitions(location);
        }
    }


    protected void doLoadBeanDefinitions(Resource resource) {
        try {
            Document doc = XmlUtil.readXML(resource.getInputStream());
            Element root = doc.getDocumentElement();
            NodeList childNodes = root.getChildNodes();
            for (int i = 0; i < childNodes.getLength(); i++) {
                if (!(childNodes.item(i) instanceof Element)) {
                    continue;
                }

                if (!("bean".equals(childNodes.item(i).getNodeName()))) {
                    continue;
                }

                Element beanNode = (Element) childNodes.item(i);
                String beanName = beanNode.getAttribute("id");
                String className = beanNode.getAttribute("class");
                String initMethodName = beanNode.getAttribute("init-method");
                String destroyMethodName = beanNode.getAttribute("destroy-method");
                String scope = beanNode.getAttribute("scope");

                Class clazz = Class.forName(className);

                BeanDefinition beanDefinition = new BeanDefinition(clazz);

                if (StringUtil.isNotEmpty(beanName)) {
                    beanName = StringUtil.lowerCaseFirst(clazz.getSimpleName());
                }

                if (StringUtil.isNotEmpty(scope)) {
                    beanDefinition.setScope(scope);
                }

                beanDefinition.setInitMethodName(initMethodName);
                beanDefinition.setDestroyMethodName(destroyMethodName);

                for (int j = 0; j < beanNode.getChildNodes().getLength(); j++) {
                    if (!(beanNode.getChildNodes().item(j) instanceof Element)) {
                        continue;
                    }

                    if (!("property".equals(beanNode.getChildNodes().item(j).getNodeName()))) {
                        continue;
                    }

                    Element propertyNode = (Element) beanNode.getChildNodes().item(j);
                    String name = propertyNode.getAttribute("name");
                    Object value;

                    if (propertyNode.getAttribute("value") == null || "".equals(propertyNode.getAttribute("value"))) {
                        BeanReference ref = new BeanReference(propertyNode.getAttribute("ref"));
                        value = ref;
                    } else {
                        value = propertyNode.getAttribute("value");
                    }

                    beanDefinition.getPropertyValues().addPropertyValue(new PropertyValue(name, value));
                }

                getRegistry().registerBean(beanName, beanDefinition);
            }
        } catch (IOException | ClassNotFoundException | BeanException e) {
            e.printStackTrace();
        }
    }

}
